package cn.wolfcode.rbac.springSecurity.filter;

import cn.wolfcode.rbac.domain.Employee;
import cn.wolfcode.rbac.utils.JwtUtils;
import cn.wolfcode.rbac.utils.RedisUtils;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import static cn.wolfcode.rbac.common.RedisKeyPrefix.LOGIN_EMPLOYEE_PREFIX;

/**
 * 自定义filter
 */
@Component
public class JwtAuthenFilter extends OncePerRequestFilter {

    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private JwtUtils jwtUtils;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        /*在拦截资源的filter前先把登录的信息存入SpringSecurity的上下文中
          因为在访问资源路径
          1.先判断是否需要认证，不需要则放行
          2.如果需要认证，从上下文中获取用户信息，如果有就放行，如果没有就拦截

          解决方案：
          1.定义一个类继承 OncePerRequestFilter，并覆盖doFilterInternal
          2.在doFilterInternal方法中
           2.1 获取请求头的userId
           2.2 如果userId不为空，从redis中获取用户信息
           2.3 如果从redis获取的用户信息不为空，则把用户信息存入到 上下文中*/

        //1.从请求头从获取userId
        String loginToken = request.getHeader(jwtUtils.getHeader());
        if(!StringUtils.isEmpty(loginToken)){
            //2.根据uuid从redis中查
            //解析loginToken
            String uuid = jwtUtils.getPayload(loginToken, "uuid");
            String jsonObj = redisUtils.get(LOGIN_EMPLOYEE_PREFIX + uuid);
            if(!StringUtils.isEmpty(jsonObj)){
                //3.如果jsonObj不为空，则把jsonObj转为Employee对象
                Employee employee = JSON.parseObject(jsonObj, Employee.class);
                //4.把账号和密码封装到token中
                UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(employee.getName(), employee.getPassword());
                //5.把token存入上下文
                SecurityContextHolder.getContext().setAuthentication(token);
            }
        }
        //6.如果存入成功,则放行去执行下个filter
        filterChain.doFilter(request,response);
    }
}
